package com.grupit.engine.service.impl.mybatis.dao;

import java.io.IOException;
import java.io.Reader;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import com.grupit.engine.service.impl.mybatis.dao.generated.NoteVOMapper;

public class DaoFactory {
	public final static String MYBATIS_CONFIG_FILENAME = "/PoZitMyBatisConfig.xml";

	private static SqlSessionFactory theSqlMapper;

	public synchronized static DaoFactory openTransaction() throws IOException {
		if (theSqlMapper == null) {
			loadMyBatisConfig();
		}

		return new DaoFactory(theSqlMapper);
	}

	/**
	 * Sesión con la que se crearán los mappers
	 */
	private SqlSession session;

	private NoteVOMapper noteMapper;

	private DaoFactory(SqlSessionFactory sqlMapper) {
		/**
		 * No auto-commit
		 */
		this.session = sqlMapper.openSession(false);
	}

	private static void loadMyBatisConfig() throws IOException {
		Reader reader = Resources.getResourceAsReader(MYBATIS_CONFIG_FILENAME);
		theSqlMapper = new SqlSessionFactoryBuilder().build(reader);
	}

	public NoteVOMapper getNoteMapper() {
		assertSessionOpened();

		if (this.noteMapper == null) {
			this.noteMapper = this.session.getMapper(NoteVOMapper.class);
		}

		return this.noteMapper;
	}

	private void assertSessionOpened() {
		String assertFailedMessage = "DaoFactory - No se puede utilizar obtener un dao una vez cerrada la sesión.";
		assert (this.session != null) : assertFailedMessage;
		// Si estuviesen las aserciones deshabilitadas
		if (this.session == null) {
			throw new RuntimeException(assertFailedMessage);
		}
	}

	public synchronized void endTransaction() {
		if (this.session != null) {
			this.session.close();
			this.session = null;
		}
	}

	@Override
	protected void finalize() throws Throwable {
		super.finalize();

		endTransaction();
	}

	public void commit() {
		assertSessionOpened();

		this.session.commit();
	}

}
